package com.choosefine.paycenter.pay.mq;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.transaction.LocalTransactionExecuter;
import com.aliyun.openservices.ons.api.transaction.TransactionStatus;
import com.choosefine.paycenter.common.utils.ByteArrayStringUtils;
import com.choosefine.paycenter.common.utils.SerialNumberUtils;
import com.choosefine.paycenter.pay.constants.PayConstants;
import com.choosefine.paycenter.pay.service.PayLocalTransactionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

/**
 * Comments：支付本地事务执行器(执行本地事务成功后，才会提交消息【即投递给消费者】)
 * Author：Jay Chang
 * Create Date：2017/5/2
 * Modified By：
 * Modified Date：
 * Why & What is modified：
 * Version：v1.0
 */
@Slf4j
@Service
public class PayLocalTransactionExecuter implements LocalTransactionExecuter {

    @Autowired
    private PayLocalTransactionService payLocalTransactionService;

    @Autowired
    private SerialNumberUtils  serialNumberUtils;

    private static final String ARG_ERR_MSG = "支付本地事务执行器[LocalTransactionExecuter]的执行方法的第2个参数必须为String[只能是支付流水号或充值流水号]";

    @Override
    public TransactionStatus execute(Message message, Object argObj) {
        //消息ID(有可能消息体一样，但消息ID不一样, 当前消息属于Half 消息，所以消息ID在控制台无法查询)
        final String msgId = message.getMsgID();
        final String tag = message.getTag();
        final String jsonStr = ByteArrayStringUtils.getInstance().byteArray2String(message.getBody(),"UTF-8");
        final JSONObject payOrderMessage = JSON.parseObject(jsonStr);
        TransactionStatus transactionStatus = TransactionStatus.Unknow;
        boolean isCommit = false;
        Assert.isInstanceOf(String.class,argObj,ARG_ERR_MSG);
        final String sn = (String)argObj;
        final boolean isPaySn = serialNumberUtils.isPaySn(sn);
        final boolean isRechargeSn = serialNumberUtils.isRechargeSn(sn);
        if(!isPaySn && !isRechargeSn){
            throw new IllegalArgumentException(ARG_ERR_MSG);
        }
        //执行更改支付订单或充值单状态为成功
        //支付成功，更改支付单状态或充值单状态为成功（执行本地事务）
          try {
              if(isPaySn) {
                  if (PayConstants.PAY_TAG_PAY_SUCCESS.equals(tag)) {
                      if (serialNumberUtils.isPaySn(sn)) {//若是支付
                          payLocalTransactionService.processPaySuccess(payOrderMessage);
                      } else if (serialNumberUtils.isRechargeSn(sn)) {
                          payLocalTransactionService.processRechargeSuccess(payOrderMessage);
                      }
                      //支付失败，更改支付单或充值单状态为失败(执行本地事务)
                  } else if (PayConstants.PAY_TAG_PAY_FAILURE.equals(tag)) {
                      if (isPaySn) {
                          payLocalTransactionService.processPayFailure(payOrderMessage);
                      } else if (serialNumberUtils.isRechargeSn(sn)) {
                          payLocalTransactionService.processRechargeFailure(payOrderMessage);
                      }
                  }
              }
              if(isRechargeSn){
                  //充值是由支付系统本身发起，故bizzSys为SELF
                  payOrderMessage.put("bizzSys","SELF");
                  if(PayConstants.PAY_TAG_PAY_SUCCESS.equals(tag)){//充值成功
                        payLocalTransactionService.processRechargeSuccess(payOrderMessage);
                  } else if(PayConstants.PAY_TAG_PAY_FAILURE.equals(tag)){
                        payLocalTransactionService.processRechargeFailure(payOrderMessage);
                  }
              }
              isCommit = true;
          }catch (Exception e){
              log.error("支付本地事务处理失败Message Id:{},消息内容：{}", msgId,payOrderMessage,e);
          }
        //删除一些信息
        payOrderMessage.remove("realName");
        payOrderMessage.remove("accountId");
        message.setBody(ByteArrayStringUtils.getInstance().string2ByteArray(payOrderMessage.toJSONString(),"UTF-8"));
        //本地事务操作成功、则提交消息(投递到消费者) 否则回滚消息（不会投递给消费者）
        transactionStatus = isCommit ? TransactionStatus.CommitTransaction : TransactionStatus.RollbackTransaction;
        log.info("Message Id:{},transactionStatus:{}", msgId, transactionStatus.name());
        return transactionStatus;
    }
}
